package com.glink.manage.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glink.common.contants.BaseCodeConstants;
import com.glink.common.exception.GeneralSimpleException;
import com.glink.common.util.BaseCommonUtils;
import com.glink.manage.common.BeanKit;
import com.glink.manage.domain.RoleBean;
import com.glink.manage.dto.role.RolePageRequestDTO;
import com.glink.manage.dto.role.RoleSaveRequestDTO;
import com.glink.manage.dto.role.RoleUpdateRequestDTO;
import com.glink.manage.mapper.RoleMapper;
import com.glink.manage.service.RoleMenuRelaService;
import com.glink.manage.service.RoleService;
import com.glink.manage.service.UserRoleRelaService;
import com.glink.manage.vo.role.RoleBaseVO;
import com.glink.manage.vo.role.RoleSimpleVO;
import com.glink.manage.vo.role.RoleUserVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

@Slf4j
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, RoleBean> implements RoleService {

    @Autowired
    private RoleMenuRelaService roleMenuRelaService;
    
    @Autowired
    private UserRoleRelaService userRoleRelaService;

    @Transactional(readOnly = true)
    public RoleBean findTop(Consumer<LambdaQueryWrapper<RoleBean>> consumer) {
        return lambdaQuery()
                .and(Objects.nonNull(consumer), consumer)
                .last(" LIMIT 1 ")
                .one();
    }

    /**
     * 新增角色信息
     * @param dto 角色信息
     * @return 新增状态
     * @throws GeneralSimpleException 异常信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean insertRole(RoleSaveRequestDTO dto) throws GeneralSimpleException {
        final String roleName = dto.getName();
        final String _Id = BaseCommonUtils.nextIdAsString();
        final RoleBean other = findTop(x -> x.eq(RoleBean::getName, roleName).ne(RoleBean::getId, _Id));
        if (nonNull(other)) {
            throw new GeneralSimpleException("401002", "角色重复(id: " + other.getId() + ", name: " + roleName + "),不能新增");
        }
        RoleBean role = BeanKit.copyProperties(dto, RoleBean::new);
        role.setIfFixed(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02);
        role.setId(_Id);
        return role.insert();
    }
    
    /**
     * 默认角色: 系统默认添加的角色，不能删除
     * 固定角色: 业务功能需要的角色，不能删除
     * 其他角色:管理员手动创建的角色，可以设置用户，配置权限，编辑名称，删除角色
     *
     * @param dto 角色信息
     * @return 更新状态
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean modifyRole(RoleUpdateRequestDTO dto) throws GeneralSimpleException {
        final String roleId = dto.getRoleId();
        // update
        if (StringUtils.isNotBlank(roleId)) {
            RoleBean one = findTop(x -> x.eq(RoleBean::getId, roleId));
            if (nonNull(one)) {
                // 系统预设不支持编辑角色信息
                if(StringUtils.isNotBlank(one.getIfFixed()) &&
                        (StringUtils.equals(one.getIfFixed(), BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01)
                        || StringUtils.equals(one.getIfFixed(), "-1"))){
                    throw new GeneralSimpleException("401006", one.getName());
                }
                
                BeanKit.copyPropertiesIgnoreNull(dto, one);
                return update(one, Wrappers.lambdaQuery(RoleBean.class)
                        .eq(RoleBean::getId, roleId)
                );
            }
        }
       
        return false;
    }

    @Override
    @Transactional(readOnly = true)
    public RoleBaseVO findByRoleId(String roleId) {
        RoleBean roleBean = baseMapper.findByRoleId(roleId);
        return beanToVO(roleBean);
    }

    private RoleBaseVO beanToVO(RoleBean roleBean){
        if(Objects.isNull(roleBean)){
            return null;
        }
        RoleBaseVO roleBaseVO = new RoleBaseVO();
        BeanKit.copyProperties(roleBean, roleBaseVO);
        return roleBaseVO;
    }

    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int deleteRoleById(String roleId) throws GeneralSimpleException {
        RoleBean role = this.lambdaQuery().eq(RoleBean::getId, roleId).one();
        if(Objects.isNull(role)){
            // 角色不存在
            throw new GeneralSimpleException("401001", roleId);
        }

        // 系统预设不支持删除角色信息
        if(StringUtils.isNotBlank(role.getIfFixed()) &&
                (StringUtils.equals(role.getIfFixed(), BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01)
                ||
                StringUtils.equals(role.getIfFixed(), "-1"))){
            throw new GeneralSimpleException("401003", role.getName());
        }
        
        int deleteNum = baseMapper.delete(
                Wrappers.lambdaQuery(RoleBean.class)
                        .eq(RoleBean::getId, roleId));
        if (deleteNum > 0) {
            roleMenuRelaService.deleteByRoleId(roleId);

            userRoleRelaService.deleteByRoleId(roleId);
        }
        return deleteNum;
    }

    @Override
    @Transactional(readOnly = true)
    public IPage<RoleUserVO> getRolePage(RolePageRequestDTO dto) {
        final IPage<RoleBean> page = new Page<>(dto.getPage(), dto.getSize());

        String roleName = dto.getRoleName();

        IPage<RoleBean> roleBeanIPage = this.lambdaQuery()
                .like(StringUtils.isNotEmpty(roleName), RoleBean::getName, roleName)
                .orderByAsc(RoleBean::getCreateTime)
                .orderByAsc(RoleBean::getId).page(page);
        
        IPage<RoleUserVO> roleUserVOIPage = new Page<>(roleBeanIPage.getCurrent(), roleBeanIPage.getSize(), roleBeanIPage.getTotal());
        if(Objects.nonNull(roleBeanIPage) && CollectionUtils.isNotEmpty(roleBeanIPage.getRecords())){
            List<RoleUserVO> roleUserVOList = Lists.newArrayList();
            roleBeanIPage.getRecords().forEach( roleBean -> {
                RoleUserVO roleUserVO = new RoleUserVO();
                BeanKit.copyProperties(roleBean, roleUserVO);
                roleUserVOList.add(roleUserVO);
            });
            roleUserVOIPage.setRecords(roleUserVOList);
        }

        return roleUserVOIPage;
    }

    /**
     * 根据角色ID查询角色名称
     *
     * @param roleIdList 角色ID列表
     */
    @Override
    public List<RoleBaseVO> findRoleNameByRoleIdIn(List<String> roleIdList) {
        List<RoleBaseVO> roleNameList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(roleIdList)){
            List<RoleBean> roleBeanList = this.lambdaQuery().in(RoleBean::getId, roleIdList).list();
            if(CollectionUtils.isNotEmpty(roleBeanList)){
                roleBeanList.stream().forEach(roleBean -> {
                    roleNameList.add(beanToVO(roleBean));    
                });
                
            }
        }
        return roleNameList;
    }

    /**
     * 获取角色列表
     *
     * @return 角色列表
     */
    @Override
    public List<RoleSimpleVO> getRoleList() {
        List<RoleBean> roleBeanList = this.lambdaQuery().orderByAsc(RoleBean::getName, RoleBean::getId).list();
        List<RoleSimpleVO> simpleVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(roleBeanList)){
            roleBeanList.forEach(roleBean -> {
                simpleVOList.add(beanToSimpleVO(roleBean));
            });
        }
        return simpleVOList;
    }

    @Override
    public List<String> findRoleIdByRoleName(String defaultAdminRole) {

        List<RoleBean> roleBeanList = this.lambdaQuery().eq(RoleBean::getName, defaultAdminRole).list();
        if(CollectionUtils.isNotEmpty(roleBeanList)){
            return roleBeanList.stream().map(RoleBean::getId).collect(Collectors.toList());
        }
        return null;
    }

    private RoleSimpleVO beanToSimpleVO(RoleBean roleBean) {
        RoleSimpleVO roleSimpleVO = new RoleSimpleVO();
        BeanKit.copyProperties(roleBean, roleSimpleVO);
        return roleSimpleVO;
    }
}
